package XML;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/*
 * BUG:
 * 通过路径取对象方法不完善
 * 叶子标签不能被成为父标签
 * 
 */
//
//System.out.println("请输入字符串：");
//String line = sc.readLine();
//System.out.println("正则表达式：");
//String regex = sc.readLine();
//Pattern  pattern = Pattern.compile(regex);
//Matcher matcher = pattern.matcher(line);
//while(matcher.find()){
//	System.out.println("匹配成功:"+matcher.group()+"\tstart:"+matcher.start()+"\tend"+matcher.end());
//}
//
//================================================
//解剖标签区域块<...>
//
//请输入字符串：
//<ABC bc  = "dd'<>'dd"fff  = 'sdfasdbbb'ttt = kkkk /><ABC bc  = "dd'<>'dd"fff  = 'sdfasdbbb'ttt = kkkk/>
//正则表达式：
//<([^<>"'= ]+){1}((( *)([^<>"'= ]+)( *)[=]( *)("{1})([^"]*)("{1}))|(( *)([^<>"'= ]+)( *)[=]( *)('{1})([^']*)('{1}))|(( *)([^<>"'= ]+)( *)[=]( *)([^<>"'= /]+)))*( *)(/?)>
//匹配成功:<第三方 士大夫  = "sdfasd似的<>发射"士大夫  = 'sdfasd似的F发射'士大夫  = sdfasd似的F发射 />	start:0	end67
//
//
//=================================================
//解剖标签属性部分：
//("{1}[^"]+"{1})|('{1}[^']+'{1})|\S+|=
//
//请输入字符串：
//ABC bc  = "dd'<>'dd"fff  = 'sdfasdbbb'ttt = kkkk
//正则表达式：
//("{1}[^"]+"{1})|('{1}[^']+'{1})|\S+|=
//匹配成功:ABC	start:0	end3
//匹配成功:bc	start:4	end6
//匹配成功:=	start:8	end9
//匹配成功:"dd'<>'dd"	start:10	end20
//匹配成功:fff	start:20	end23
//匹配成功:=	start:25	end26
//匹配成功:'sdfasdbbb'	start:27	end38
//匹配成功:ttt	start:38	end41
//匹配成功:=	start:42	end43
//匹配成功:kkkk	start:44	end48

/**
 * XML文档类
 * 
 * @author sky.Wind
 */
public class XML extends XMLNode implements Cloneable {
	public static final int TOP = 0;
	public static final int BUTTOM = -1;
	public static final int FRONT = 1;
	public static final int BACK = 2;
	/**
	 * 不区分大小写
	 */
	public static boolean like(String format, String value) {
		return like(format, value, false);
	}
	/**
	 * 模拟SQL的通配符条件判断。 ? % _ [abc1-9] 注意 %_ 是错误个通配字符串
	 * 
	 * @param format
	 *            格式字符串 如：邮箱：%@%_
	 * @param value
	 *            被判断的值 yiyongpeng@tom.com<br>
	 *            如过null则返回false;
	 * @param sensitive
	 *            是否区分大小写，true为区分
	 * @return 是否匹配
	 */
	public static boolean like(String format, String value, boolean sensitive) {
		if (value == null)
			return false;
		if (!sensitive) {
			format = format.toUpperCase();// 不区分大小写
			value = value.toUpperCase();
		}
		boolean k = false;// 是否范围通配
		ArrayList<String> als = new ArrayList<String>();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < format.length(); i++) {
			char ch = format.charAt(i);
			if (k && ch != ']')
				sb.append(ch);// 范围字符截取
			else
				switch (ch) {
				case '[':
					if (sb.length() > 0) {
						als.add(sb.toString());
						sb.setLength(0);
					}
					k = true;
					break;
				case ']':
					k = false;
					// System.out.println("范围通配符:"+sb);
					if (sb.length() > 0) {
						als.add("[" + sb + "]");
						sb.setLength(0);
					}
					break;
				case '%':
					if (sb.length() > 0) {
						// System.out.println(sb.toString());
						als.add(sb.toString());
						// if(!value.startsWith(sb.toString()))return false;
						sb.setLength(0);
					}
					als.add("%");
					break;
				case '_':
					if (sb.length() > 0) {
						// System.out.println(sb.toString());
						als.add(sb.toString());
						// if(!value.startsWith(sb.toString()))return false;
						sb.setLength(0);
					}
					als.add("_");
					break;
				default:
					sb.append(ch);
				}
		}
		if (sb.length() > 0)
			als.add(sb.toString());
		/* [qq, %, dd, _, dd, %] "qq%dd_dd%","qq dd ddssss" */
		// System.out.println(als);
		sb.replace(0, sb.length(), value);
		while (als.size() > 0) {
			// if(sb.length()==0)return false;//没有待通配的字符串，但还有通配字符，返回假
			String str = als.get(0);
			// System.out.println("!~!" + str);
			if (str.charAt(0) == '[' && str.charAt(str.length() - 1) == ']') {
				// 取出待通配字符串第一个字符
				char ch = sb.charAt(0);
				sb.delete(0, 1);
				if (str.indexOf(ch) == -1)
					return false;
				als.remove(0);
			} else if (str.equals("%")) {
				// System.out.println(als.toString()+sb);
				if (als.size() > 1) {
					str = als.get(1);
					int kl = sb.indexOf(str);
					// System.out.println("!%!" + sb);
					if (kl == -1)
						return false;
					sb.replace(0, kl + str.length(), "");
					als.remove(0);
					als.remove(0);
				} else {
					// System.out.println("通配通过");
					return true;
				}
			} else if (str.equals("_")) {
				als.remove(0);
				sb.replace(0, 1, "");
			} else {
				if (sb.toString().startsWith(str)) {
					sb.replace(0, str.length(), "");
					als.remove(0);
				} else {
					// System.out.println("字符串通配失败：" + str + " -> " + sb);
					return false;
				}
			}
		}
		if (sb.length() > 0)
			return false;// 待通配字符串有剩余，返回假
		// System.out.println("通配符: " + format + " = " + value);
		return true;
	}

	public static XMLNode parseFlag(String substring) {
		return parseFlag(null, substring);
	}

	/**
	 * 解析&lt;a href="www.MicCity.net"&gt;中间的标签信息为对象
	 * 
	 * @param Supper
	 *            父标签对象
	 * @param f
	 *            标签内容信息
	 * @return 返回标签对象
	 */
	public static XMLNode parseFlag(XMLNode Super, String f) {
		/* 解析标签属性开始 */
		StringBuffer sb = new StringBuffer(f);
		int i = f.indexOf(' ');
		String fg = f.substring(0, i != -1 ? i : f.length());// 获得属性名
		sb.replace(0, i != -1 ? i + 1 : fg.length(), "");
		f = sb.toString();
		// System.out.println("[解析标签]"+(Super==null?" ":("
		// supper:"+Super.FLAG+"\t"))+"flag:" + fg + (f.length()>0?("\tData:" +
		// f.length()):""));
		XMLNode hf = new XMLNode(Super, fg);// 构造标签对象
		String attribute = null;// 属性名备份
		hf.setLeafage(f.length() > 0 && f.charAt(f.length() - 1) == '/');
		if (hf.isLeafage())// 判断是否为叶子标签
			f = f.substring(0, f.length() - 1);
		boolean fz = false;// 是否遇到赋值符号
		boolean all = false;// 值区域开关
		StringBuffer data = new StringBuffer(0);

		for (i = 0; i < f.length(); i++) {
			char ch = f.charAt(i);// 读字符
			if (ch == '"' || ch == '\'') {
				// System.out.println(all?"字符串:关闭":"字符串:开");
				if (all) {
					// System.out.println(attribute + " = " + data.toString());
					if (attribute != null)
						hf.put(attribute, data.toString());
					data.setLength(0);
					attribute = null;
					all = fz = false;
				} else
					all = true;// 字符串值开关
			} else if (all) {
				data.append(ch);
			} else if (ch == ' ') {
				if (data.length() != 0) {// 判断缓冲区是否有数据
					if (fz) {
						// System.out.println("_ " + attribute + " = "
						// + data.toString());
						hf.put(attribute, data.toString());
						data.setLength(0);
						attribute = null;
						fz = all = false;
					} /*
					 * else { attribute = data.toString();// 确认属性名
					 * data.setLength(0);// 清空缓冲区
					 * System.out.println("Flag:"+hf+" 属性名:"+attribute); }
					 */
				}
			} else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
				data.append(ch);
			} else if (ch == '=') {
				attribute = data.toString();// 确认属性名
				data.setLength(0);// 清空缓冲区
				fz = true;// 标记遇到赋值符号
				all = false;
				// System.out.println("= Flag:"+hf+" 属性名:"+attribute);
			} else {// 判断是否在字符串值区域
				data.append(ch);
			}
		}
		if (attribute != null && data.length() != 0) {
			hf.put(attribute, data.toString());
			// System.out.println("@ " + attribute + " = " + data.toString());
		}
		/* 解析标签属性结束 */
		return hf;
	}

	private Vector<XMLNode> al = new Vector<XMLNode>(0);// 构建标签对象容器

	String xml = null;

	public XML() {
		super(null, null);
	}

	public XML(File file) {
		this();
		parseHTML(read(file));
	}

	public XML(String html) {
		this();
		parseHTML(html);
	}

	public XML(Vector<XMLNode> al) {
		this();
		this.al = al;
	}

	public XML(XMLNode xf) {
		this();
		this.copy(xf);
	}

	/**
	 * 将结构标签对象集合添加到指定标签下面
	 * 
	 * @param path
	 *            指定标签路径
	 * @param h
	 *            被添加标签集合
	 * @param local
	 *            添加位置 TOP BUTTOM FRONT BACK
	 * @return 添加根节点标签数量
	 */
	public int add(String path, XML h, int local) {
		if (h == null)
			return 0;// 对象空不能添加
		XMLNode hf = null;// 父标签对象
		if (path != null && path.length() > 0) {
			Object obj = GetPathValue(path);// 索引标签对象
			hf = obj != null ? (XMLNode) obj : null;
			if (hf == null)
				return 0;// 对象路径不存在
		}
		return add(h, hf, local);
	}

	/**
	 * 默认追加到后面
	 * 
	 * @param path
	 *            路径
	 * @param x
	 */
	public void add(String path, XMLNode x) {
		add(path, x, XML.BUTTOM);
	}

	/**
	 * 将标签对象添加到指定标签下面
	 * 
	 * @param PATH
	 *            指定标签路径，null或空文本表示置顶层
	 * @param h
	 * @param local
	 *            TOP BUTTOM FRONT BACK
	 * @return
	 */
	public boolean add(String path, XMLNode h, int local) {
		if (h == null)
			return false;// 对象空不能添加
		XMLNode hf = null;
		if (path != null && path.length() > 0) {
			Object obj = GetPathValue(path);// 索引标签对象
			hf = obj != null ? (XMLNode) obj : null;
			if (hf == null)
				return false;// 对象路径不存在
		}
		return add(hf, h, local);
	}

	/**
	 * 将结构标签对象集合添加到指定标签下面
	 * 
	 * @param h
	 *            被添加标签集合
	 * @param hf
	 *            指定标签
	 * @param local
	 *            添加位置
	 * @return 添加数量
	 */
	public int add(XML h, XMLNode hf, int local) {
		// System.out.println("[addFlag]"+h+","+hf+","+local);
		Vector<XMLNode> als = h.getArrayList();
		int k = 0;
		if (hf != null)
			k = al.indexOf(hf);// 获取指定标签索引位置

		int j = 0;
		boolean b = (local == BUTTOM);// 是否放在最后
		for (int i = (b ? 0 : (als.size() - 1)); (b ? i < als.size() : i >= 0); i += b ? 1 : -1) {
			XMLNode tmp = als.get(i);
			if (tmp.getSUPER() == null) {// 设置父级标签
				tmp.setSUPER(hf == null ? null : local == FRONT || local == BACK ? hf.getSUPER() : hf);
				j++;
			}
			switch (local) {
			case TOP:
				al.add(0, tmp);// 将对象插入到顶端
				break;
			case BUTTOM:
				// System.out.println("_"+tmp);
				al.add(tmp);// 插到底部
				break;
			case FRONT:
				al.add(hf == null || k == -1 ? 0 : k, tmp);// 前面
				// System.out.println("<<|"+k+" "+tmp);
				break;
			case BACK:
				int n = al.size();
				al.add(hf != null ? (k + 1 < n ? k + 1 : n - 1) : n - 1, tmp);// 后面
				break;
			}
		}
		return j;
	}

	/**
	 * 将一个标签对象添加到指定标签对象位置
	 * 
	 * @param aim
	 *            目标标签对象,null表示最顶层
	 * @param hf
	 *            被添加标签
	 * @param local
	 *            添加位置
	 * @return 是否添加成功
	 */
	public boolean add(XMLNode aim, XMLNode hf, int local) {

		if (hf == null || (aim != null && al.indexOf(aim) == -1))
			return false;
		hf.setSUPER(aim == null ? null : (local == FRONT || local == BACK) ? aim.getSUPER() : aim);// 修改父对象
		if (aim != null && aim.isLeafage())
			aim.setLeafage(false);
		switch (local) {
		case TOP:
			al.add(0, hf);// 将对象插入到顶端
			break;
		case BUTTOM:
			al.add(hf);// 插到底部
			break;
		case FRONT:
			al.add(aim != null ? al.indexOf(aim) : 0, hf);// 前面
			break;
		case BACK:
			int i = al.indexOf(aim) + 1;// 计算添加位置
			int n = al.size() - 1;// 获得最后一个标签的索引
			al.add(aim == null ? n : (i > 0 ? i : n), hf);// 后面
			break;
		}
		return true;
	}

	public void clear() {
		al.clear();
	}

	/**
	 * 克隆一个相同的实例
	 */
	@Override
	public XML clone() {
		return new XML(createCode(false, ""));
	}

	/**
	 * 生成源代码字符串（自定义缩进或换行）
	 * 
	 * @param newline
	 *            是否换行
	 * @param indent
	 *            缩进字符
	 * @return
	 */
	public String createCode(boolean newline, String indent) {
		StringBuffer str = (xml != null ? new StringBuffer("<?" + xml + "?>\r\n") : (new StringBuffer()));
		if (al.size() == 0 && FLAG != null && FLAG.length() > 0) {
			str.append(super.toString());
		}
		str.append(createCode(null, 0, indent, newline));
		return str.toString();
	}

	/**
	 * 生成源代码到文件,默认重写文件
	 * 
	 * @param f
	 * @return
	 */
	public boolean createCode(File f) {
		boolean suc = createCode(f, false);
//		System.out.println("保存XML数据文件,"+f+", "+suc);
		return suc;
	}

	/**
	 * 生成源代码到文件
	 * 
	 * @param f
	 * @param ap
	 *            是否追加
	 * @return 是否写入成功
	 */
	public boolean createCode(File f, boolean ap) {
		String str = createCode(true, "\t");
		if (str == null)
			return false;

		try {
			if (!f.exists())
				f.createNewFile();// 创建文件
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}

		try {
			PrintWriter fw = new PrintWriter(f);// 创建写文件流
			fw.println(str);
			fw.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			f.delete();// 出现异常删除文件
		}
		return false;
	}

	/**
	 * 生成源代码到文件，默认重写文件
	 * 
	 * @param filename
	 *            文件路径名
	 * @return
	 */
	public boolean createCode(String filename) {
		return createCode(new File(filename), false);
	}

	/**
	 * 生成源代码到文件
	 * 
	 * @param filename
	 *            文件路径名
	 * @param ap
	 *            是否追加
	 * @return
	 */
	public boolean createCode(String filename, boolean ap) {
		return createCode(new File(filename), ap);
	}

	/**
	 * 生成指定节点标签下的子标签源代码
	 * 
	 * @param h
	 *            指定标签
	 * @param k
	 *            缩进层数
	 * @param indent
	 *            缩进字符
	 * @param newline
	 *            是否换行
	 * @return
	 */
	public String createCode(XMLNode h, int k, String indent, boolean newline) {
		Vector<XMLNode> als = new Vector<XMLNode>();
		getList(als, h, false);// 枚举子标签
		StringBuffer sb = new StringBuffer();

		// System.out.println("createCode:"+h+":"+als);
		for (int i = 0; i < als.size(); i++) {
			XMLNode hf = als.get(i);
			String str = tabStr(indent, k) + hf.toString();
			sb.append(str);
			str = createCode(hf, k + 1, indent, newline);// 生成子标签源码
			if (str.length() > 0) {
				int j = sb.length() - (hf.FLAG.length() + 3);// 取修饰内容结束位置
				sb.insert(j, newline ? "\r\n" : "" + tabStr(indent, k));// 插入换行
				j += newline ? 2 : 0;
				sb.insert(j, str);
			}
			sb.append(newline ? "\r\n" : "");// 追加换行符
		}
		return sb.toString();
	}

	/**
	 * 获取结构标签集合
	 * 
	 * @return
	 */
	public Vector<XMLNode> getArrayList() {
		return al;
	}

	/**
	 * 取标签数
	 * 
	 * @return
	 */
	public int getCount() {
		return al.size();
	}

	/**
	 * 通过ID获取对象
	 * 
	 * @param id
	 * @return null表示未找到
	 */
	public XMLNode getFlagObj(String id) {
		XMLNode xf = null;
		for (int i = 0; i < al.size(); i++) {
			xf = al.get(i);
			if (xf != null) {
				String ids = xf.get("id").toString();// 取属性值
				if (ids != null && ids.equals(id)) {
					return xf;
				}
			}
		}
		return null;
	}

	/**
	 * 通过父对象读取指定标签名“标签对象”
	 * 
	 * @param Super
	 *            父标签对象
	 * @param Flag
	 *            标签名字 或 id 值
	 * @return 标签对象
	 */
	public XMLNode getHF(XMLNode Super, String f) {
		// System.out.println(Super + " < " + f);
		String str;

		for (int i = 0; i < al.size(); i++) {
			XMLNode h = al.get(i);// 取当前检测标签
			if (h.getSUPER() == Super) {// 查找Super子标签
				if (f.charAt(0) == '#') {// 选择以id属性或标签名索引
					str = h.get("id").toString();
					if (str != null) {
						boolean t = str.equals(f.substring(1, f.length()));
						if (t)
							return h;
					}
				} else if (h.FlagHomology(f))// 验证标签名
					return h;
			}
		}
		return null;
	}

	public int getInt(String name) {
		String v = get(name);
		if (v != null) {
			return Integer.parseInt(v);
		}
		return 0;
	}

	/**
	 * 修饰内容条件通配遍历指定标签对象下的子标签
	 * 
	 * @param als
	 *            标签对象结果集合
	 * @param hf
	 *            欲遍历标签对象
	 * @param data
	 *            修饰内容通配字符串,通配符:%[abc]_
	 * @param child
	 *            是否遍历所有子标签对象
	 * @return 返回遍历数量
	 */
	public int getList(ArrayList<XMLNode> als, XMLNode hf, String data, boolean child) {
		// System.out.println("[内容枚举]patch:" + getPath(hf) + "\t\tDATA:" + hf);
		int j = 0;
		for (int i = 0; i < al.size(); i++) {
			XMLNode h = al.get(i);
			if (h.getSUPER() == hf) {
				if (like(data, h.getData(true))) {// 通配字符串验证
					als.add(h);
					j++;
				}
				if (child)
					j += getList(als, h, data, true);// 枚举所有子标签对象
			}
		}
		return j;
	}

	/**
	 * 属性条件通配枚举标签对象
	 * 
	 * @param als
	 *            标签对象结果集
	 * @param hf
	 *            指定的标签，null表示枚举所有标签
	 * @param att
	 *            属性名
	 * @param value
	 *            通配值,通配符:%[abc]_
	 * @param child
	 *            是否枚举所有子标签对想
	 * @return 枚举数量
	 */
	public int getList(ArrayList<XMLNode> als, XMLNode hf, String att, String value, boolean child) {
		String[] att1 = new String[1];
		String[] value1 = new String[1];
		att1[0] = att;
		value1[0] = value;
		return getList(als, hf, att1, value1, child);
	}

	/**
	 * 属性条件通配枚举标签对象
	 * 
	 * @param als
	 *            标签对象结果集
	 * @param hf
	 *            指定的标签，null表示枚举所有标签
	 * @param att
	 *            [] 属性名数组
	 * @param value
	 *            [] 通配值数组,通配符:%[abc]_
	 * @param child
	 *            是否枚举所有子标签对想
	 * @return 枚举数量
	 */
	public int getList(ArrayList<XMLNode> als, XMLNode hf, String[] att, String[] value, boolean child) {
		// System.out.println("[属性枚举]patch:" + getPath(hf) + "\t\t属性名:"
		// + att.length + "\t通配值:" + value.length);
		int j = 0;
		for (int i = 0; i < al.size(); i++) {
			XMLNode h = al.get(i);
			if (h.getSUPER() == hf) {
				// ---属性通配验证开始---
				boolean b = true;
				String str;
				for (int k = 0; k < att.length; k++)
					if (null == (str = h.get(att[k]).toString()) ? true : !like(value[k], str)) {
						b = false;// 含有通配失败的属性,或没有此属性
						break;
					}
				if (b) {
					als.add(h);
					j++;
				}
				// ----属性通配验证结束---
				if (child)
					j += getList(als, h, att, value, true);// 枚举所有子标签对象
			}
		}
		return j;
	}

	/**
	 * 枚举指定标签对象下的子标签对象列表
	 * 
	 * @param als
	 *            结果集合
	 * @param hf
	 *            指定标签
	 * @param child
	 *            是否枚举所有子标签
	 * @return 枚举数量
	 */
	public int getList(List<XMLNode> als, XMLNode hf, boolean child) {
		// System.out.println("[定向枚举]patch:" + getPath(hf) + "\t\tDATA:" +
		// hf+(hf!=null?" super:"+hf.getSUPER():""));
		int j = 0;
		for (int i = 0; i < al.size(); i++) {
			XMLNode hfs = al.get(i);
			if (hfs.getSUPER() == hf) {
				als.add(hfs);
				j++;
				if (child)
					j += getList(als, hfs, true);// 枚举子标签
			}
		}
		return j;
	}

	/**
	 * 修饰内容条件通配遍历指定标签路径下的子标签
	 * 
	 * @param path
	 *            null或空字符表示遍历所有标签，如："html.body"
	 * @param als
	 *            标签结果集合
	 * @param data
	 *            修饰内容的模糊条件,,通配符:%[abc]_
	 * @param child
	 *            是否遍历所有子标签
	 * @return 返回遍历数量
	 */
	public int getList(String path, ArrayList<XMLNode> als, String data, boolean child) {
		XMLNode hf = null;
		if (path != null && path.length() > 0) {
			Object obj = GetPathValue(path);
			hf = obj != null ? (XMLNode) obj : null;
			if (hf == null) {
				// System.out.println("路径不存在，" + path);
				return 0;// 路径不存在
			}
		}
		return getList(als, hf, data, child);
	}

	/**
	 * 属性条件通配枚举标签对象
	 * 
	 * @param path
	 *            签路径， null 表示枚举所有标签
	 * @param als
	 *            标签对象结果集合
	 * @param att
	 *            属性名
	 * @param value
	 *            通配值,通配符:%[abc]_
	 * @param child
	 *            是否枚举子标签
	 * @return 枚举数量
	 */
	public int getList(String path, ArrayList<XMLNode> als, String att, String value, boolean child) {
		String[] att1 = new String[1];
		String[] value1 = new String[1];
		att1[0] = att;
		value1[0] = value;
		return getList(path, als, att1, value1, child);
	}

	/**
	 * 删除首尾空格字符
	 * 
	 * @param str
	 * @return
	 */
//	public String strEntity(String str) {
//		StringBuffer sb = new StringBuffer(str);
	// System.out.print(""+str + "(->)");
//		char ch;
//		try {
//			while ((ch = sb.charAt(0)) == ' ' || ch == '\r' || ch == '\n'
//					|| ch == '\t')
//				sb.deleteCharAt(0);
//			while ((ch = sb.charAt(sb.length() - 1)) == ' ' || ch == '\r'
//					|| ch == '\n' || ch == '\t')
//				sb.deleteCharAt(sb.length() - 1);
//		} catch (Exception e) {
//		}
	// System.out.println(sb.toString());
//		return sb.toString();
//	}

	/**
	 * 属性条件通配枚举标签对象
	 * 
	 * @param path
	 *            标签路径， null或空字符 表示枚举所有标签
	 * @param als
	 *            标签对象结果集合
	 * @param att
	 *            [] 属性名数组
	 * @param value
	 *            [] 通配值数组,通配符:%[abc]_
	 * @param child
	 *            是否枚举子标签
	 * @return 枚举数量
	 */
	public int getList(String path, ArrayList<XMLNode> als, String att[], String[] value, boolean child) {
		XMLNode hf = null;
		if (path != null && path.length() > 0) {
			Object obj = GetPathValue(path);
			hf = obj != null ? (XMLNode) obj : null;
			if (hf == null) {
				// System.out.println("路径不存在，" + path);
				return 0;// 路径不存在
			}
		}
		return getList(als, hf, att, value, child);
	}

	/**
	 * 枚举指定标签路径下的子标签列表
	 * 
	 * @param path
	 *            null或空字符串表示取顶层标签
	 * @param als
	 * @param child
	 *            是否包含二代子标签
	 * @return
	 */
	public int getList(String path, List<XMLNode> als, boolean child) {
		XMLNode hf = null;
		if (path != null && path.length() > 0) {
			Object obj = GetPathValue(path);
			hf = obj != null ? (XMLNode) obj : null;
			if (hf == null) {
				// System.out.println("路径不存在，" + path);
				return 0;// 路径不存在
			}
		}
		// System.out.println("[定向枚举]patch:" + path + "\t\tDATA:" +
		return getList(als, hf, child);
	}

	/**
	 * 取标签索引路径
	 * 
	 * @param h
	 * @return
	 */
	public String getPath(XMLNode h) {
		int i = al.indexOf(h);// 检测是否存在
		if (i == -1)
			return null;

		String id = h.get("id").toString();
		String str = id == null ? h.FLAG : "#" + id;// id值优先
		if (h.getSUPER() != null)
			str = getPath(h.getSUPER()) + "." + str;
		return str;
	}

	/**
	 * 读取指定标签属性值，(以#为前缀则同过id属性值索引)<br>
	 * HTML.body.table:align :表示取table的align属性值（允许将“:”替换成“.”）<br>
	 * HTML.body.#12.href #12表示body标签的子标签中id=12 的标签<br>
	 * HTML.body.table 表示取table在集合容器中HtmlFlag类的实例<br>
	 * 
	 * @param objURL
	 *            索引标签的路径，用 . 来索引<br>
	 * @return 字符串属性值 或 HtmlFlag对象 null 表示没有指定标签或属性
	 */
	public Object GetPathValue(String objURL) {
		if (objURL == null)
			return null;
		String str = null;
		int i = 0;
		String URL = objURL.substring(0, (i = objURL.lastIndexOf(':')) != -1 ? i : objURL.length());// 初始化标签路径
		String att = i != -1 ? objURL.substring(i + 1, objURL.length()) : null;// 初始化属性名
		// System.out.println(URL + " > " + att);

		i = 0;
		XMLNode Super = null;
		try {

			do {
				str = URL.substring(i, (i = URL.indexOf('.', i + 1)) != -1 ? i : URL.length());// 取标签名
				String flg = str.charAt(0) == '.' ? str.substring(1, str.length()) : str;// 去点

				// System.out.println("SELECT:" + Super + " Flag:" + flg);
				XMLNode hf = getHF(Super, flg);// 通过父对象索引指定标签
				if (hf == null) {
					if (URL.endsWith(str)) {// 判断当前标签名是否为URL最后一个名字（转取属性）
						return Super != null ? Super.get(flg) : null;// 没有对象则作为取属性值
						// ，并返回值
					} else {
						// System.out.println(str + "/" + flg + " => null");
						return null;
					}
				} else {
					Super = hf;
				}
				// System.out.println("FLAG:" + Super);
			} while (i != -1);
			if (att != null) {
				str = !att.toUpperCase().equals("DATA") ? Super.get(att) : Super.getData(true);// 读取属性值
																								// data表示读修饰内容
				// System.out.println("~~"+Super+str);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
		return att != null ? str : Super;// 是否
	}

	/**
	 * 自动解析HTML文件为结构化标签对象（树）
	 * 
	 * @param f
	 */
	public void parseHTML(File f) {
		parseHTML(read(f));
	}

	/**
	 * 自动解析HTML源代码为结构化标签对象（树）
	 * 
	 * @param h
	 *            源代码
	 */
	public void parseHTML(String h) {
		al.clear();// 清空标签对象容器
		// boolean bosom=false;//是否在标签<>内部
		StringBuffer data = new StringBuffer(0);
		XMLNode Super = null;
		int start = h.indexOf('<')// 初始化"<"开始位置
		, end = h.indexOf('>', start);// 初始化">"结束位置
		XMLNode flag;// 临时标签对象

		while (start != -1 && end != -1) {
			data.replace(0, data.length(), h.substring(start + 1, end).trim());// 取标签数据内容
			char ch = data.charAt(0);
			switch (ch) {
			case '?':// xml 版本信息
				xml = data.substring(1, data.length() - 1);
				break;
			case '!':// 注释信息
				flag = new XMLNode(Super, "!");
				flag.setData(h.substring(start+4, h.indexOf("-->", start+4)));
//				flag.put("id", String.valueOf(start));
				al.add(flag);
				break;
			case '/':// 结束标签
				Super = Super == null ? null : Super.getSUPER();// 标签回溯(遇到</?>标签)
				break;
			default:// 解析标签对象,null表示结束标签
				flag = parseFlag(Super, data.toString());
				// ----截取修饰内容开始----
				int i = h.indexOf('<', end);
				if (i != -1 && i - end > 0) {
					String str = h.substring(end + 1, i);
					flag.setData(str);
				}
				// ----截取修饰内容结束----
				al.add(flag);// 新增标签
				Super = flag.isLeafage() ? Super : flag;// 标记栈顶标签,叶标签不标记
			}
			start = h.indexOf('<', end);
			end = (start == -1 ? -1 : h.indexOf('>', start));
		}
	}

	/**
	 * 将文件中的内容读取到字符串对象中
	 * 
	 * @param f
	 *            要读取的
	 * @return 文件f中的Text内容
	 * @throws IOException
	 */
	public String read(File f) {
		// 创建读文件流
		StringBuffer sb = new StringBuffer();
		try {
			FileReader fr = new FileReader(f);
			BufferedReader br = new BufferedReader(fr);
			String str;
			while ((str = br.readLine()) != null) {
				sb.append(str);
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return sb.toString();
	}

	/**
	 * 移除指定路径标签节点
	 * 
	 * @param path
	 *            标签路径，不能为null
	 * @param child
	 *            仅子标签
	 * @return 结构标签集合
	 */
	public XML remove(String path, boolean child) {
		Object obj = GetPathValue(path);
		if (obj == null) {
			return null;
		}
		XMLNode hf = (XMLNode) obj;
		return remove(hf, child);
	}

	public XML remove(XMLNode hf) {
		return remove(hf, false);
	}

	/**
	 * 移除指定标签对象包括所有子标签
	 * 
	 * @param hf
	 *            指定标签对象,不能为空
	 * @param child
	 *            仅移除子标签
	 * @return
	 */
	public XML remove(XMLNode hf, boolean child) {
		if (hf == null || al.indexOf(hf) == -1)
			return null;

		Vector<XMLNode> als = new Vector<XMLNode>();
		int i = getList(als, hf, false);// 枚举指定标签下的子标签

		if (i > 0) {
			// 枚举子标签下的所有子标签
			Vector<XMLNode>[] alh = new Vector[als.size()];
			for (i = 0; i < als.size(); i++) {
				alh[i] = new Vector<XMLNode>();
			}// 初始化结束
			for (int j = 0; j < als.size(); j++) {
				// 枚举子标签下的所有标签
				getList(alh[j], als.get(j), true);// 枚举所有子节点标签
			}
			// 集合所有枚举到的标签到结果集中
			for (int j = 0; j < alh.length; j++)
				als.addAll(alh[j]);
		}
		if (!child) {
			hf.setSUPER(null);
			als.add(0, al.remove(al.indexOf(hf)));// 将指定的标签转移到新的标签集合中去
		}
		XML xml = new XML(als);// 构造结构标签集合对象
		for (i = child ? 0 : 1; i < als.size(); i++) {
			int j = al.indexOf(als.get(i));
			if (j != -1)
				al.remove(j);// 移除节点标签下的所有标签
		}
		return xml;
	}

	/**
	 * 取指定数量字符
	 * 
	 * @param str
	 * @param i
	 * @return
	 */
	private String tabStr(String str, int k) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < k; i++) {
			sb.append(str);
		}
		return sb.toString();
	}

	@Override
	public String toString() {
		return createCode(false, "");
	}

	/**
	 * 更新标签的修饰内容
	 * 
	 * @param path
	 * @param value
	 * @return
	 */
	public boolean updata(String path, String value) {
		Object obj = GetPathValue(path);
		XMLNode hf = obj != null ? (XMLNode) obj : null;
		if (hf == null)
			return false;

		hf.setData(value);
		return true;
	}

	/**
	 * 更新标签指定属性的值
	 * 
	 * @param path
	 * @param att
	 * @param value
	 * @return
	 */
	public boolean updata(String path, String att, String value) {
		Object obj = GetPathValue(path);
		XMLNode hf = obj != null ? (XMLNode) obj : null;
		if (hf == null || att == null)
			return false;

		hf.put(att, value);
		return true;
	}

}
